python面向对象(四)

深入理解引用与拷贝

引用的理解

  • 引用:类似于C语言的指针,多个变量名/对象名可以指向同一块内存数据。

    每个对象存在至少1个引用。

    python中一切都是对象,一切标识名称都是真实对象的引用。

    1
    2
    3
    4
    5
    6
    7
    8
    li = [1,3,4]
    lt = li
    id(li)
    id(lt)
    '''
    1955588376200
    1955588376200
    '''
  • python内部机制对引用的处理

    • 不可变对象:immutable 解释器为相同值维护尽量少的内存区域
    • 可变对象:mutable 解释器为每个对象维护不同内存区域
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    a = 'aaa'
    b = a
    c = 'a'
    d = 'aa'
    e = c + d
    f = 'aaa'
    for i in [a,b,c,d,e,f]:
    print(id(i))
    '''
    2438022394856
    2438022394856
    2438022277416
    2438025612456
    2438025476112
    2438022394856
    '''
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    a = []
    b = a
    c = []
    for i in [a,b,c]:
    print(id(i))

    '''
    1955587514632
    1955587514632
    1955587201480
    '''
  • 查看某个对象被多少标识名称引用,即查看对象被引用了多少次:

    sys.getrefcount()返回值为 被引用次数+1

  • 导致引用+1的情况:

    • 对象被创建:d = list()
    • 对象被引用:a = d
    • 对象被作为函数或方法的参数:sys.getrefcount(d)
    • 对象被作为一个容器中的元素:ls = [d]
  • 导致引用-1的情况:

    • 对象被删除:del d
    • 对象的名字被赋予新的对象:d = 123
    • 对象离开作用域:foo()函数的局部变量count
    • 对象所在容器被删除:del ls

      方法/函数的引用

方法或函数也是对象,方法名/函数名是它的一个引用。

对象名.方法名(方法参数) 等价于 类名.方法名(对象名, 方法参数)

1
2
3
4
5
6
7
8
def func(a, b):
return a+b
a = func
print(a(1,2))

'''
3
'''
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class A(object):
def hi(self, name):
print('hi %s' % name)


a = A()
hi = a.hi
A.hi(a, '老哥')
a.hi('老哥')
hi('老哥')

'''
hi 老哥
hi 老哥
hi 老哥
'''

浅拷贝和深拷贝

拷贝:复制一个对象为内存空间中新的对象。

浅拷贝:仅复制最顶层对象的拷贝方式,默认

深拷贝:迭代复制对象内所有层次的对象的拷贝方式。深拷贝仅针对可变类型,不可变类型无需创建新对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import copy  
ls = ['aaa', [1, 2, 3]]

# 浅拷贝
la = ls.copy()
# la = copy.copy(ls)
lb = ls[:]
lc = list(ls)

for i in [ls, la, lb, lc]:
print('id:', id(i))
for ele in i:
print('\t', ele, id(ele), end=' ')
print()

'''
id: 2648396751560
aaa 2648397214696 [1, 2, 3] 2648396751496
id: 2648517817160
aaa 2648397214696 [1, 2, 3] 2648396751496
id: 2648398020744
aaa 2648397214696 [1, 2, 3] 2648396751496
id: 2648400455176
aaa 2648397214696 [1, 2, 3] 2648396751496
'''
'''
可以看出浅拷贝时,在内存中新建了列表内存对象,但并没有拷贝列表内的元素
'''
#=======================================
# 深拷贝

ld = copy.deepcopy(ls)
for i in [ls, ld]:
print('id:', id(i))
for ele in i:
print('\t', ele, id(ele), end=' ')
print()

'''
id: 2156262417096
aaa 2156262880232 [1, 2, 3] 2156262417032
id: 2156383348872
aaa 2156262880232 [1, 2, 3] 2156266148168
'''
'''
深拷贝迭代复制所有包含的对象
'''